#!/bin/bash
# 目录指定，最终会在这个目录下 增加/发布单/项目
# /Users/wangjie/code/java/马来-ipo
# clone_dir="$HOME/meili/vangelis.wang/103/Documents/code/ops"
clone_dir="$HOME/code/java/ops"
# 此文件用于保存配置。勿动
clone_config_file="ops.properties"
# 确保配置目录存在


# 日志函数
log() {
    echo "$(date +'%Y-%m-%d %H:%M:%S') - $1"
}

# 打开idea
open_idea(){
    echo "$3 $2 下载完成"
    # shellcheck disable=SC2162
    read -p "是否打开IntelliJ IDEA？(y/n): " open_confirm
    if [ "$open_confirm" == "y" ]; then
        open -a "IntelliJ IDEA Ultimate" "$1"
    fi
}

# 格式化名字这种，去掉系统不支持的
format_name(){
    # shellcheck disable=SC2001
    echo "$1" | sed 's|/|_|g'
}

request_permission(){
  # shellcheck disable=SC2155
  local data=$(jq -n --arg write_repo "$1" \
     '{
       "write": [$write_repo],
       "read": [],
       "subject": "开发需求",
       "inform_member": "alvin.hu"
     }')
  # 发起请求并捕获响应
  RESPONSE=$(curl -s "https://vops.hszq8.com/app/api/v1/apply/create/asc/asc" \
    -H "Accept: application/json, text/plain, */*" \
    -H "Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6" \
    -H "Connection: keep-alive" \
    -H "Content-Type: application/json;charset=UTF-8" \
    -H "Cookie: vops_token=$2" \
    -H "Origin: https://vops.hszq8.com" \
    -H "Referer: https://vops.hszq8.com/app/permissions_request_asc" \
    -H "Sec-Fetch-Dest: empty" \
    -H "Sec-Fetch-Mode: cors" \
    -H "Sec-Fetch-Site: same-origin" \
    -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0" \
    -H 'sec-ch-ua: "Chromium";v="130", "Microsoft Edge";v="130", "Not?A_Brand";v="99"' \
    -H 'sec-ch-ua-mobile: ?0' \
    -H 'sec-ch-ua-platform: "macOS"' \
    --data-raw "$data")
  # 解析 JSON 响应并进行校验
  message=$(echo "$RESPONSE" | jq -r '.message')
  log "申请结果: $message 请检查申请结果(飞书审批)"
}

# 克隆项目 1. clone地址 2. 项目地址 3. 分支名字
clone_project(){
    # 检查项目文件夹是否存在
    if [ -d "$1" ]; then
        log "项目文件夹 '$1' 已经存在。跳过不处理"
        return 0
    fi

    # 执行克隆并捕获错误信息
    clone_output=$(git clone "$2" "$1" 2>&1)  # 捕获标准错误输出
    if echo "$clone_output" | grep -q "could not be found\|don't have permission"; then
        log "无权限访问仓库或仓库不存在：$2 尝试申请中..."
        request_permission "$2" "$4"
        return 1
    fi

    # 切换到指定分支
    cd "$1" && git checkout "$3"
    # shellcheck disable=SC2181
    if [ $? -ne 0 ]; then
        log "克隆 $2 失败"
        return 1
    fi

    return 0
}

# 写入配置的函数
write_config() {
    local key=$1
    local value=$2
    # 如果 key 已存在，替换它的值；否则追加新的 key-value
    if grep -q "^$key=" "$clone_config_file"; then
        sed -i '' "s/^$key=.*/$key=$value/" "$clone_config_file"
    else
        echo "$key=$value" >> "$clone_config_file"
    fi
}

# 读取配置的函数
read_config() {
    local key=$1
    # 使用 grep 提取 key 的值
    value=$(grep "^$key=" "$clone_config_file" | cut -d'=' -f2)
    echo "$value"
}
# 追加配置的函数
append_config() {
    local key=$1
    local new_value=$2
    # 获取当前 key 的值
    # shellcheck disable=SC2155
    local old_value=$(read_config "$key")
    # 如果 key 存在且不为空，则追加新值；否则直接写入新值
    if [ -n "$old_value" ]; then
        # 确保不重复追加相同的值
        if [[ "$old_value" != *"$new_value"* ]]; then
            new_value="$old_value,$new_value"
        else
            echo "值 '$new_value' 已存在于 '$key'，跳过追加。"
            return 0
        fi
    fi

    # 写入更新后的值
    write_config "$key" "$new_value"
}

# 处理发布单。返回ops项目信息
parse_url() {
  # 普通发布单
  if [[ $1 == *"flow_type"* && $1 == *"flow_id"* ]]; then
    log "普通发布单模式"
        # 解析URL参数
    flow_type=$(echo "$1" | awk -F'[?&]' '{for(i=1;i<=NF;i++){if($i ~ /^flow_type=/){split($i,a,"="); print a[2]}}}')
    flow_id=$(echo "$1" | awk -F'[?&]' '{for(i=1;i<=NF;i++){if($i ~ /^flow_id=/){split($i,a,"="); print a[2]}}}')
    # 检查是否成功提取了flow_type和flow_id
    if [ -z "$flow_type" ] || [ -z "$flow_id" ]; then
        log "错误：无法解析flow_type和flow_id，请检查输入的URL。流程终止。"
        exit 1
    fi
     if [ -n "$3" ]; then
        # 用户输入的默认位置存在且不为空字符串
        log "用户输入的默认位置为：$3"
        clone_dir="$clone_dir/$3"
      else
        work_item_name=$(get_flow_detail "https://vops.hszq8.com/app/api/v1/flow/get_flow_detail?type=$flow_type&id=$flow_id" "$2" ".data.work_item_name")
        clone_dir="$clone_dir/$work_item_name"
      fi
    mkdir -p "$clone_dir"
    clone_config_file="$clone_dir/$clone_config_file"
    # 如果配置文件不存在，创建它
    if [ ! -f "$clone_config_file" ]; then
        touch "$clone_config_file"
    fi
    log "解析发布单 成功  flow_id：$flow_id 下载目录：$clone_dir 配置文件: $clone_config_file"
    append_config "type" "1"
    write_config "ops_url" "$1"
    write_config "ops_type" "发布单模式"
    write_config "flow_id" "$flow_id"
    write_config "flow_type" "$flow_type"
    api_response=$(get_flow_project "https://vops.hszq8.com/app/api/v1/flow/get_app_and_branch?type=$flow_type&id=$flow_id" "$2")
    # 解析data里面的项目信息
    projects=$(echo "$api_response" | jq -r '.data | length')
    log "发布单中总项目个数: $projects"
     # shellcheck disable=SC2004
     # 初始化app_list为空字符串
    app_list=""
    # 先在主进程中构建app_list
    # shellcheck disable=SC2004
    for ((i=0; i<$projects; i++)); do
      # ops项目名
      app=$(echo "$api_response" | jq -r ".data[$i].app")
      flow_app_id=$(echo "$api_response" | jq -r ".data[$i].id")
      repo_url=$(format_repo_url "$(echo "$api_response" | jq -r ".data[$i].repo_url")")
      # 分支名
      branch=$(echo "$api_response" | jq -r ".data[$i].name")
      repo_name=$(basename "$repo_url" .git)
      write_config "project.$repo_name.opsName" "$app"
      write_config "project.$repo_name.flow_app_id" "$flow_app_id"
      write_config "project.$app.path" "$repo_name"
      write_config "project.$repo_name.source.branch" "$branch"
      # 拼接app到app_list，使用逗号分隔
      if [ -z "$app_list" ]; then
          app_list="$app"    # 初始值时不加逗号
      else
          app_list="$app_list,$app"
      fi
    done
    log "$app_list 写入配置文件"
    append_config "apps" "$app_list"

    # shellcheck disable=SC2004
    for ((i=0; i<$projects; i++)); do
      {
      # git地址。http的版本
      repo_url=$(format_repo_url "$(echo "$api_response" | jq -r ".data[$i].repo_url")")
      # 分支名
      branch=$(echo "$api_response" | jq -r ".data[$i].name")
      # ops项目名
      app=$(echo "$api_response" | jq -r ".data[$i].app")
      # 文件夹的名字 也是git项目名
      repo_name=$(basename "$repo_url" .git)
      log "项目名：$repo_name 分支名称: $branch, 仓库URL: $repo_url  app: $app"
      # 构建项目文件夹路径
      project_dir="$clone_dir/$repo_name"
      clone_project "$project_dir" "$repo_url" "$branch" "$2"
      } &

    done
  wait
  # shellcheck disable=SC2031
  open_idea "$clone_dir" "$1" "发布单"
  exit 1
  fi
  # 依赖发布单
  if [[ $1 == *"release/app"* || $1 == *"release/deps"* ]]; then
    log "依赖发布单模式"
    param=$(basename "$1")
    if [ -n "$3" ]; then
        # 用户输入的默认位置存在且不为空字符串
        log "用户输入的默认位置为：$3"
        clone_dir="$clone_dir/$3"
    else
      work_item_name=$(get_flow_detail "https://vops.hszq8.com/app/api/v1/release/$param/info" "$2" ".data.name")
      clone_dir="$clone_dir/$work_item_name"
    fi
    mkdir -p "$clone_dir"
    clone_config_file="$clone_dir/$clone_config_file"
    # 如果配置文件不存在，创建它
    if [ ! -f "$clone_config_file" ]; then
        touch "$clone_config_file"
    fi
    log "解析依赖发布单 成功  url参数：$param 下载目录：$clone_dir 配置文件: $clone_config_file"
    append_config "type" "2"
    write_config "ops_support_url" "$1"
    write_config "ops_type_support" "依赖发布单模式"
    write_config "param" "$param"
    api_response=$(get_flow_project "https://vops.hszq8.com/app/api/v1/release/$param/app" "$2")
     # 解析data里面的项目信息
     projects=$(echo "$api_response" | jq -r '.data | length')
     log "依赖发布单中总项目个数: $projects"
    # shellcheck disable=SC2004
    for ((i=0; i<$projects; i++)); do
      # ops项目名
      app=$(echo "$api_response" | jq -r ".data[$i].appname")
      repo_url=$(format_repo_url "$(echo "$api_response" | jq -r ".data[$i].scm")")
      # 分支名
      branch=$(echo "$api_response" | jq -r ".data[$i].branch")
      repo_name=$(basename "$repo_url" .git)
      write_config "project.support.$repo_name.opsName" "$app"
      write_config "project.support.$repo_name.source.branch" "$branch"
      # 拼接app到app_list，使用逗号分隔
      if [ -z "$app_list" ]; then
          app_list="$app"    # 初始值时不加逗号
      else
          app_list="$app_list,$app"
      fi
    done
    log "$app_list 写入配置文件"
    write_config "support_apps" "$app_list"
    # 下载项目
     # shellcheck disable=SC2004
     for ((i=0; i<$projects; i++)); do
     {
       # git地址。http的版本
       repo_url=$(format_repo_url "$(echo "$api_response" | jq -r ".data[$i].scm")")
       # 分支名
       branch=$(echo "$api_response" | jq -r ".data[$i].branch")
       # ops项目名
       app=$(echo "$api_response" | jq -r ".data[$i].appname")
       # 文件夹的名字 也是git项目名
       repo_name=$(basename "$repo_url" .git)
       log "项目名：$repo_name 分支名称: $branch, 仓库URL: $repo_url  app: $app"
       # 构建项目文件夹路径
       project_dir="$clone_dir/$repo_name"
        # 检查项目文件夹是否存在
       clone_project "$project_dir" "$repo_url" "$branch" "$2"
       } &
     done
    wait
    # shellcheck disable=SC2031
    open_idea "$clone_dir" "$1" "依赖发布单"
    exit 1

  fi
  # 发布计划
  if [[ $1 == *"plan_detail"* ]]; then
    log "发布计划模式"
    id=$(echo "$1" | awk -F'[?&]' '{for(i=1;i<=NF;i++){if($i ~ /^id=/){split($i,a,"="); print a[2]}}}')
    if [ -z "$id" ]; then
        log "错误：无法解析id，请检查输入的URL。流程终止。"
        exit 1
    fi
    if [ -n "$3" ]; then
      # 用户输入的默认位置存在且不为空字符串
      log "用户输入的默认位置为：$3"
      clone_dir="$clone_dir/$3"
    else
      work_item_name=$(get_flow_detail "https://vops.hszq8.com/app/api/v1/flow_plan/detail/$id" "$2" ".data.title")
      clone_dir="$clone_dir/$work_item_name"
    fi
    mkdir -p "$clone_dir"
    clone_config_file="$clone_dir/$clone_config_file"
    # 如果配置文件不存在，创建它
    if [ ! -f "$clone_config_file" ]; then
        touch "$clone_config_file"
    fi
    log "解析发布计划 成功  id：id 下载目录：$clone_dir 配置文件: $clone_config_file"
    append_config "type" "3"
    write_config "ops_plan_url" "$1"
    write_config "ops_plan_type" "发布计划模式"
    write_config "plan_id" "$id"
    api_response=$(get_flow_project "https://vops.hszq8.com/app/api/v1/flow_plan/plan_version_branch/$id" "$2")
    # 解析data里面的项目信息
    projects=$(echo "$api_response" | jq -r '.data | length')
    log "发布计划中总项目个数: $projects"

     # shellcheck disable=SC2004
     # 初始化app_list为空字符串
    app_list=""
    # 先在主进程中构建app_list
    # shellcheck disable=SC2004
    for ((i=0; i<$projects; i++)); do
      # ops项目名
      app=$(echo "$api_response" | jq -r ".data[$i].app")
      repo_url=$(format_repo_url "$(echo "$api_response" | jq -r ".data[$i].repo_url")")
      # 分支名
      branch=$(echo "$api_response" | jq -r ".data[$i].name")
      repo_name=$(basename "$repo_url" .git)
      write_config "project.$repo_name.opsName" "$app"
      write_config "project.$app.path" "$repo_name"
      write_config "project.$repo_name.source.branch" "$branch"
      # 拼接app到app_list，使用逗号分隔
      if [ -z "$app_list" ]; then
          app_list="$app"    # 初始值时不加逗号
      else
          app_list="$app_list,$app"
      fi
    done
    log "$app_list 写入配置文件"
    write_config "apps" "$app_list"

    # shellcheck disable=SC2004
    for ((i=0; i<$projects; i++)); do
    {
      # git地址。http的版本
      repo_url=$(format_repo_url "$(echo "$api_response" | jq -r ".data[$i].repo_url")")
      # 分支名
      branch=$(echo "$api_response" | jq -r ".data[$i].name")
      # ops项目名
      app=$(echo "$api_response" | jq -r ".data[$i].app")
      # 文件夹的名字 也是git项目名
      repo_name=$(basename "$repo_url" .git)
      log "项目名：$repo_name 分支名称: $branch, 仓库URL: $repo_url  app: $app"
      # 构建项目文件夹路径
      project_dir="$clone_dir/$repo_name"
      clone_project "$project_dir" "$repo_url" "$branch" "$2"
      } &
    done
    wait
    # shellcheck disable=SC2031
    open_idea "$clone_dir" "$1" "发布计划"
    exit 1
  fi
  log "错误：不支持的地址"
  exit 1
}



# 获取token
get_vops_token() {
  # 1. 调用接口获取git地址数组
  vops_result=$(curl -s https://admin-feature.vbkrhk.com/auto-ai/vops/user/effective/token)
  # 使用jq来提取data字段的值
  token=$(echo "$vops_result" | jq -r '.data')
  # 校验data是否有值
  if [ -z "$token" ]; then
    echo "响应中的data字段为空，流程终止。"
    exit 1
  fi
  echo "$token"
}

# git地址换成http地址
format_repo_url(){
  if [[ $1 == git@* ]]; then
    # 提取域名和仓库路径
    domain=$(echo $1 | sed -E 's/git@([^:]+):.*/\1/')
    path=$(echo $1 | sed -E 's/git@[^:]+:(.*)/\1/')
    # 构建 HTTP 地址
    repo_url="http://$domain/$path"
    echo "$repo_url"
  else
    echo "$1"
  fi
}

# 获取发布单的名字
get_flow_detail(){
   api_detail_response=$(curl -s  "$1" \
            -H 'Accept: application/json, text/plain, */*' \
            -H 'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6' \
            -H 'Connection: keep-alive' \
            -H "Cookie: vops_token=$2" \
            -H 'Referer: https://vops.hszq8.com/app/flow/flow_detail' \
            -H 'Sec-Fetch-Dest: empty' \
            -H 'Sec-Fetch-Mode: cors' \
            -H 'Sec-Fetch-Site: same-origin' \
            -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0' \
            -H 'sec-ch-ua: "Chromium";v="124", "Microsoft Edge";v="124", "Not-A.Brand";v="99"' \
            -H 'sec-ch-ua-mobile: ?0' \
            -H 'sec-ch-ua-platform: "macOS"')
          # 打印请求返回的body内容
    # 检查status是否为success
    status=$(echo "$api_detail_response" | jq -r '.status')
    if [ "$status" != "success" ]; then
      log "get_flow_detail调用失败，返回状态为 $status 。流程终止。"
      exit 1
    fi
    work_item_name=$(format_name "$(echo "$api_detail_response" | jq -r "$3")")
    echo "$work_item_name"
}
# 获取发布单的项目
get_flow_project(){
   api_response=$(curl -s "$1" \
        -H 'Accept: application/json, text/plain, */*' \
        -H 'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6' \
        -H 'Connection: keep-alive' \
        -H "Cookie: vops_token=$2" \
        -H 'Referer: https://vops.hszq8.com/app/flow/flow_detail' \
        -H 'Sec-Fetch-Dest: empty' \
        -H 'Sec-Fetch-Mode: cors' \
        -H 'Sec-Fetch-Site: same-origin' \
        -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0' \
        -H 'sec-ch-ua: "Chromium";v="124", "Microsoft Edge";v="124", "Not-A.Brand";v="99"' \
        -H 'sec-ch-ua-mobile: ?0' \
        -H 'sec-ch-ua-platform: "macOS"')
      # 检查status是否为success
      status=$(echo "$api_response" | jq -r '.status')
      if [ "$status" != "success" ]; then
        log "get_app_and_branch 调用失败，返回状态为 $status 。流程终止。"
        exit 1
      fi
      echo "$api_response"
}


# 定义帮助信息
show_help() {
  ## 检查配置信息
  type=$(read_config "type")
  # 使用 IFS 分隔字符串为数组
  IFS=',' read -r -a types <<< "$type"
  # 遍历数组，并根据条件拼接字符串
  for t in "${types[@]}"; do
      case "$t" in
          1)
              result+="普通发布单"
              ;;
          2)
              result+="依赖发布单"
              ;;
          3)
              result+="发布计划"
              ;;
          *)
      esac
  done

   echo "用法: ops [选项 or url]"
   echo "即可快速获取发布单、依赖发布单、发布计划中的项目"
   echo "选项:"
   echo "  -r                   更新配置文件"
   echo "  url                  获取该发布单信息，拉取项目，如无权限，则自动申请权限。等待授权后，再自动下载项目"
   echo "  --help               显示此帮助信息"
   echo ""
}

# 主流程
# shellcheck disable=SC1073
main() {
  if [ $# -eq 0 ]; then
      log "错误：请至少提供一个参数。"
      show_help
      exit 1
  fi
  # 获取用户输入的地址
  args=("$@")
  # 1. 获取能用的token
  token=$(get_vops_token)
  # 打印获取到的token
  log "获取 ops token: $token"
  # 解析命令行参数
  while [[ "${args[0]}" != "" ]]; do
    case $1 in
      -r)
        # 重新加载ops
        ;;
      --help)
        show_help  # 调用帮助函数
        exit 0  # 添加这行，在显示帮助后退出程序
        ;;
      *)
        # shellcheck disable=SC2001
        ops_url=$(echo "${args[0]}" | sed 's/\\//g')
        ops_base_path="${args[1]}"
        log "地址：$ops_url 下载位置：$ops_base_path"
        parse_url "$ops_url" "$token" "$ops_base_path"
        ;;
    esac
    shift
  done
}

# 执行主流程
main "$@"